package com.bearingnavi.android.views;

import android.content.Context;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.bearingnavi.android.util.Mathematics;
import com.bearingnavi.android.util.SmoothCanvas;

public class RotateView extends ViewGroup {
    private static final float SQ2 = 1.414213562373095f;
    private final SmoothCanvas mCanvas = new SmoothCanvas();
    private float bearing;
    private static RotateView instance;
    private boolean enabled = true;

    private RotateView(Context context) {
        super(context);
    }
    
    public void setBearing(float bearing) {
    	if (enabled) {
        	this.bearing = bearing;
		}
	}
    
    public void rotate(float angle) {
    	this.bearing = Mathematics.ClipAngleTo0_360(angle+this.bearing);
    	invalidate();
	}
	
	public float getBearing() {
		return bearing;
	}
	
	public static RotateView createInstance(Context context) {
		instance = new RotateView(context);
		return instance;
	}
	
	public static RotateView getInstance() {
		return instance;
	}

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save(Canvas.MATRIX_SAVE_FLAG);
        canvas.rotate(-bearing, getWidth() * 0.5f, getHeight() * 0.5f);
        mCanvas.setDelegate(canvas);
        super.dispatchDraw(mCanvas);
        canvas.restore();
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int width = getWidth();
        final int height = getHeight();
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            final View view = getChildAt(i);
            final int childWidth = view.getMeasuredWidth();
            final int childHeight = view.getMeasuredHeight();
            final int childLeft = (width - childWidth) / 2;
            final int childTop = (height - childHeight) / 2;
            view.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int w = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        int h = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
        int sizeSpec;
        if (w > h) {
            sizeSpec = MeasureSpec.makeMeasureSpec((int) (w * SQ2), MeasureSpec.EXACTLY);
        } else {
            sizeSpec = MeasureSpec.makeMeasureSpec((int) (h * SQ2), MeasureSpec.EXACTLY);
        }
        final int count = getChildCount();
        for (int i = 0; i < count; i++) {
            getChildAt(i).measure(sizeSpec, sizeSpec);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
    	
    	if (event.getPointerCount() > 1) {
    		return super.dispatchTouchEvent(event);
		}
    	
        float[] coords = new float[] {
                event.getX(), event.getY()
        };
        adjustCoords(coords, bearing);
        MotionEvent evt = MotionEvent.obtain(event.getDownTime(), event.getEventTime(), event
                .getAction(), coords[0], coords[1], event.getPressure(), event.getSize(), event
                .getMetaState(), event.getXPrecision(), event.getYPrecision(), event.getDeviceId(),
                event.getEdgeFlags());
        return super.dispatchTouchEvent(evt);
    }
    
    
    protected void adjustCoords(float[] coords, float deg) {
        float x = coords[0];
        float y = coords[1];
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;
        // convert to radians
        float rad = (float) ((deg * Math.PI) / 180F);
        float s = (float) Math.sin(rad);
        float c = (float) Math.cos(rad);
        // translate point back to origin:
        x -= centerX;
        y -= centerY;
        // apply rotation
        float tmpX = x * c - y * s;
        float tmpY = x * s + y * c;
        x = tmpX;
        y = tmpY;
        // translate point back:
        x += centerX;
        y += centerY;
        coords[0] = x;
        coords[1] = y;
    }
    
    public void disableRotating(boolean zeroMap) {
    	if (zeroMap) {
    		setBearing(0);	
		}
    	this.enabled = false;
	}
    
    public void enableRotating() { this.enabled = true; }
    
    public boolean isRotatingEnabled() { return enabled; }
    
}
